package com.ea.eadp.nexus.test.common.ApiClients;

import com.ea.eadp.nexus.test.common.FacebookTestUser;
import com.ea.eadp.nexus.test.common.SystemProperties;
import com.ea.eadp.nexus.test.common.TestUtil;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by ChuanYe on 7/24/2014.
 */
public class FacebookApi extends NexusApiBase {
    private static FacebookApi instance;

    public synchronized static FacebookApi instance() {
        if(instance == null) {
            instance = new FacebookApi();
        }
        instance.client = NexusHttpClients.getFacebookClient();
        return instance;
    }

    private static String facebookUrl = "https://graph.facebook.com/";
    private static String facebookAppId = "1024309317599461";
    private static String facebookAccessToken = "1024309317599461%7c0a02626dc7f8e9c87df14b562996aca1";
    private static String facebookProxyHost = SystemProperties.instance().getProperty(SystemProperties.FacebookProxyHost,"");
    private static String facebookProxyPort = SystemProperties.instance().getProperty(SystemProperties.FacebookProxyPort,"");
    private static String facebookClientSecret= "0a02626dc7f8e9c87df14b562996aca1";
    private static String redirectUri = "http://localhost";

    private static final Random random = new Random();

    private String getPostFacebookTestUserUrl() {
        StringBuilder sb = new StringBuilder();
        sb.append("https://graph.facebook.com:443/1024309317599461/accounts/test-users");

        String s = sb.toString();
        return s;
    }

    private String getGetAllFacebookTestUserUrl() {
        StringBuilder sb = new StringBuilder();
        sb.append(facebookUrl);
        sb.append(facebookAppId);
        sb.append("/accounts/test-users?access_token=");
        sb.append(facebookAccessToken);
        sb.append("&limit=1000");
        return sb.toString();
    }

    private String getDeleteFacebookTestUserUrl(String userId) {
        StringBuilder sb = new StringBuilder();
        sb.append(facebookUrl);
        sb.append(userId);
        sb.append("?method=delete&access_token=");
        sb.append(facebookAccessToken);
        String s = sb.toString();
        return s;
    }

    public FacebookTestUser postFacebookTestUser() throws Exception {
        String[] testNames={"John","Michelle","David","Sunny","James","Maria","Michael","Sarah","Robert","William","Jessica","Peter",
        "Thomas","Daniel","Kevin","Angela","Charles","Jason"};
        String testName="nexustest"+testNames[random.nextInt(testNames.length)] ;
        String url = getPostFacebookTestUserUrl();
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(6);
        nameValuePairs.add(new BasicNameValuePair("installed", "true"));
        nameValuePairs.add(new BasicNameValuePair("name", testName));
        nameValuePairs.add(new BasicNameValuePair("locale", "en_US"));
        nameValuePairs.add(new BasicNameValuePair("permission", "read_stream"));
        nameValuePairs.add(new BasicNameValuePair("method", "post"));
        nameValuePairs.add(new BasicNameValuePair("access_token", facebookAccessToken));
        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        HttpContext httpContext = new BasicHttpContext();
        HttpResponse response = post(httpPost, httpContext);//client.execute(httpPost, httpContext);
        String body = IOUtils.toString(response.getEntity().getContent());
        try {
            FacebookTestUser u = TestUtil.parseJson(body, FacebookTestUser.class);
            return u;
        } catch (UnrecognizedPropertyException e) {
            log.info(e.getMessage());
            throw new Exception(body);
        }
    }

    public void cleanUpFacebookTestUser() throws Exception {
        List<String> usersList = new ArrayList<String>();

        HttpGet httpGet = new HttpGet(getGetAllFacebookTestUserUrl());
        HttpContext httpContext = new BasicHttpContext();
        HttpResponse response = get(httpGet, httpContext);//client.execute(httpPost, httpContext);
        String body = IOUtils.toString(response.getEntity().getContent());
        Pattern pattern = Pattern.compile("\"id\":\"(\\d+)\"");
        Matcher matcher = pattern.matcher(body);
        while(matcher.find()){
            usersList.add(matcher.group(1));
        }

        for(String userId : usersList) {
            deleteFacebookTestUser(userId);
        }
    }

    //need to delete the facebook user everytime because there is a max limit of test facebook users under an AppId
    public void deleteFacebookTestUser(String userId) throws Exception {
        HttpDelete httpDelete = new HttpDelete(getDeleteFacebookTestUserUrl(userId));
        HttpResponse response = delete(httpDelete, null);

        String body = IOUtils.toString(response.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = response.getStatusLine().getStatusCode();
        if (status != 200) {
            log.warn("delete facebook user " + userId + "failed");
        }
    }

    public String getLongLiveAccessToken(String fbExchangeToken) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append(facebookUrl);
        sb.append("oauth/access_token?fb_exchange_token=");
        sb.append(fbExchangeToken);
        sb.append("&grant_type=fb_exchange_token&client_id=");
        sb.append(facebookAppId);
        sb.append("&client_secret=");
        sb.append(facebookClientSecret);

        HttpGet httpGet = new HttpGet(sb.toString());
        DefaultHttpClient client = NexusHttpClients.getFacebookClient();
        HttpResponse response = get(httpGet, null);

        String body = IOUtils.toString(response.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = response.getStatusLine().getStatusCode();
        if (status != 200) {
            log.warn("get longlive accesstoken failed ");
        }
        String token = body.substring("access_token=".length());
        return token;
    }

    public String getCode(String longliveToken) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append(facebookUrl);
        sb.append("oauth/client_code?access_token=");
        sb.append(longliveToken);
        sb.append("&client_id=");
        sb.append(facebookAppId);
        sb.append("&redirect_uri=");
        sb.append(redirectUri);
        sb.append("&client_secret=");
        sb.append(facebookClientSecret);

        HttpGet httpGet = new HttpGet(sb.toString());
        DefaultHttpClient client = NexusHttpClients.getFacebookClient();
        HttpResponse response = get(httpGet, null);

        String body = IOUtils.toString(response.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = response.getStatusLine().getStatusCode();
        if (status != 200) {
            log.warn("get auth code failed ");
        }
        String code = body.substring("\"code\":\"".length()+1);
        code = code.substring(0, code.length()-2);
        return code;
    }

    public String getTokenByCode(String code) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append(facebookUrl);
        sb.append("oauth/access_token?code=");
        sb.append(code);
        sb.append("&client_id=");
        sb.append(facebookAppId);
        sb.append("&redirect_uri=");
        sb.append(redirectUri);

        HttpGet httpGet = new HttpGet(sb.toString());
        DefaultHttpClient client = NexusHttpClients.getFacebookClient();
        HttpResponse response = get(httpGet, null);

        String body = IOUtils.toString(response.getEntity().getContent());
        log.info("RESPONSE BODY: " + body);
        int status = response.getStatusLine().getStatusCode();
        if (status != 200) {
            log.warn("get auth code failed ");
        }
        String token = body.substring("\"access_token\":\"".length()+1,body.indexOf("machine_id")-3);
        return token;
    }

    public String refreshToken(String fbToken) throws Exception {
        String llToken = getLongLiveAccessToken(fbToken);
        String code = getCode(llToken);
        String token = getTokenByCode(code);
        return token;
    }

    //number or special character is not allowed in FB user name
    private String randomFBUser() {
        String allowedChars = "abcdefghijklmnopqrstuvwxyz";
        StringBuilder randomStr = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            randomStr.append(allowedChars.charAt(random.nextInt(allowedChars.length())));
        }
        //return "nexustest" + randomStr.toString();
        return "nexustestjoey";
    }
}
